package animalManagement;

/**
 * A SortedListOfImmutables represents a sorted collection of immutable objects
 * that implement the Listable interface.
 * 
 * An array of references to Listable objects is used internally to represent
 * the list.
 * 
 * The items in the list are always kept in alphabetical order based on the
 * names of the items. When a new item is added into the list, it is inserted
 * into the correct position so that the list stays ordered alphabetically by
 * name.
 */
public class SortedListOfImmutables {

	/*
	 * STUDENTS: You may NOT add any other instance variables to this class!
	 */
	private Listable[] items;

	/**
	 * This constructor creates an empty list by creating an internal array of
	 * size 0. (Note that this is NOT the same thing as setting the internal
	 * instance variable to null.)
	 */
	public SortedListOfImmutables() {
		items = new Listable[0];
	}

	/**
	 * Copy constructor. The current object will become a copy of the list that
	 * the parameter refers to.
	 * 
	 * The copy must be made in such a way that future changes to either of
	 * these two lists will not affect the other. In other words, after this
	 * constructor runs, adding or removing things from one of the lists must
	 * not have any effect on the other list.
	 * 
	 * @param other
	 *            the list that is to be copied
	 */
	public SortedListOfImmutables(SortedListOfImmutables other) {
		items = new Listable[other.getSize()];
		for (int i = 0; i < other.getSize(); i++) {
			items[i] = other.get(i);
		}

	}

	/**
	 * Returns the number of items in the list.
	 * 
	 * @return number of items in the list
	 */
	public int getSize() {
		return items.length;
	}

	/**
	 * Returns a reference to the item in the ith position in the list.
	 * (Indexing is 0-based, so the first element is element 0).
	 * 
	 * @param i
	 *            index of item requested
	 * @return reference to the ith item in the list
	 */
	public Listable get(int i) {
		return items[i];
	}

	/**
	 * Adds an item to the list. This method assumes that the list is already
	 * sorted in alphabetical order based on the names of the items in the list.
	 * 
	 * The new item will be inserted into the list in the appropriate place so
	 * that the list will remain alphabetized by names.
	 * 
	 * In order to accommodate the new item, the internal array must be re-sized
	 * so that it is one unit larger than it was before the call to this method.
	 * 
	 * @param itemToAdd
	 *            refers to a Listable item to be added to this list
	 */
	public void add(Listable itemToAdd) {

		int position = 0;
		//checks if items is not empty
		if(items.length != 0){
			for(int i = 0; i < items.length; i++){
				//when itemToAdd comes alphabetically after the current
				//item in items
				if(items[i].getName().compareTo(itemToAdd.getName()) > 0){
					position = i;
					break;
					//when itemToAdd comes alphabetically in the same position
					//as the current item in items
				}else if(items[i].getName().compareTo(itemToAdd.getName()) == 0){
					position = i +1;
					break;
				}else{
					position = items.length;
				}
			}
			Listable[] temp = new Listable[items.length+1];
			int j = 0;//index for temp
			//copy elements of items array till before the point where the item
			//ToAdd is supposed to be inserted
			for(int i = 0; i < position; i++ ){
				temp[j] = items[i];
				j++;
			}
			temp[position] = itemToAdd;//add itemToAdd in the correct position
			//copy the rest of elements in items
			//to temp
			for(int k = position; k < items.length; k++){
				temp[k+1] = items[k];
			}
			items = temp; 

		}else{//if items is empty
			items = new Listable[1];
			items[0] = itemToAdd;
		}

	}

	/**
	 * Adds an entire list of items to the current list, maintaining the
	 * alphabetical ordering of the list by the names of the items.
	 * 
	 * @param listToAdd
	 *            a list of items that are to be added to the current object
	 */
	public void add(SortedListOfImmutables listToAdd) {
		//check if listToAdd is empty
		if (listToAdd.getSize() != 0) {
			for (int i = 0; i < listToAdd.getSize(); i++) {
				add(listToAdd.get(i));

			}

		}

	}

	/**
	 * Removes an item from the list.
	 * 
	 * If the list contains the same item that the parameter refers to, it will
	 * be removed from the list.
	 * 
	 * If the item appears in the list more than once, just one instance will be
	 * removed.
	 * 
	 * If the item does not appear on the list, then this method does nothing.
	 * 
	 * @param itemToRemove
	 *            refers to the item that is to be removed from the list
	 */
	public void remove(Listable itemToRemove) {

		int position = -1;
		Listable[] temp;
		for(int i = 0; i < items.length; i++){ 
			//get the position of element to be removed and then break
			if(items[i].getName().compareTo(itemToRemove.getName()) == 0){
				position = i;
				break;
			}
		}
		//when itemToRemove is not present, let the length of temp array be
		//same as items' otherwise subtract one from it
		if(position == -1){
			temp = new Listable[items.length];
		}else{
			temp = new Listable[items.length -1];
		}
		//copy everything
		if(position == -1){
			for(int m = 0; m < items.length; m++){
				temp[m] = items[m];

			}

		}

		//copy everything except the item that is to be removed
		//this is done by skipping over that position
		if(position != -1){
			for(int j = 0; j < position; j++){
				temp[j] = items[j];
			}

			for(int k = position; k < items.length -1; k++){
				temp[k] = items[k+1];
			}
		}
		items = temp;

	}

	/**
	 * Removes an entire list of items from the current list. Any items in the
	 * parameter that appear in the current list are removed; any items in the
	 * parameter that do not appear in the current list are ignored.
	 * 
	 * @param listToRemove
	 *            list of items that are to be removed from this list
	 */
	public void remove(SortedListOfImmutables listToRemove) {
		//check if the list is empty
		if (listToRemove.getSize() != 0) {
			for (int i = 0; i < listToRemove.getSize(); i++) {
				remove(listToRemove.get(i));
			}
		}
	}

	/**
	 * Returns the sum of the wholesale costs of all items in the list.
	 * 
	 * @return sum of the wholesale costs of all items in the list
	 */
	public int getWholesaleCost() {
		int sum = 0;
		for (int i = 0; i < items.length; i++) {
			//keep adding the wholesale cost of each one
			sum += items[i].getWholesaleCost();
		}
		return sum;
	}

	/**
	 * Returns the sum of the retail values of all items in the list.
	 * 
	 * @return sum of the retail values of all items in the list
	 */
	public int getRetailValue() {
		int sum = 0;
		for (int i = 0; i < items.length; i++) {
			//keep adding the retail value of each one
			sum += items[i].getRetailValue();
		}
		return sum;
	}

	/**
	 * Checks to see if a particular item is in the list.
	 * 
	 * @param itemToFind
	 *            item to look for
	 * @return true if the item is found in the list, false otherwise
	 */
	public boolean checkAvailability(Listable itemToFind) {
		boolean found = false;
		for (int i = 0; i < items.length; i++) {
			//go through all items in items to match with itemToFind, if found,
			//return true
			if (itemToFind.equals(items[i])) {
				found = true;
			}
		}
		return found;
	}

	/**
	 * Checks if a list of items is contained in the current list. (In other
	 * words, this method will return true if ALL of the items in the parameter
	 * are contained in the current list. If anything is missing, then the
	 * return value will be false.) If the list of items given as the parameter
	 * has duplicates then the list in the current object must have at least
	 * that many of the item as well.
	 * 
	 * @param listToCheck
	 *            list of items that may or may not be a subset of the current
	 *            list
	 * @return true if the parameter is a subset of the current list; false
	 *         otherwise
	 */
	public boolean checkAvailability(SortedListOfImmutables listToCheck) {
		boolean available = false;
		//check if list is empty
		if (listToCheck.getSize() != 0) {
			int count = 0;
			for (int i = 0; i < items.length; i++) {
				for(int j = 0; j < listToCheck.getSize(); j++){
					//when two items found are same in both the lists,
					//add one to count
					if(listToCheck.get(j).equals(items[i])){
						count++;
						break;
					}

				}
				//when count is the same as listToCheck, we know we have all
				//of them available
				if(count == listToCheck.getSize()){
					available= true;
					break;
				}
			}
		}
		return available;
	}

	/*
	 * Do not modify this method or you will fail our tests!
	 */
	public String toString() {
		String retValue = "[ ";
		for (int i = 0; i < items.length; i++) {
			if (i != 0) {
				retValue += ", ";
			}
			retValue += items[i];
		}
		retValue += " ]";
		return retValue;
	}
}
